#include <my_header.h>
typedef struct train_s
{
    int length;
    char data[1000];
}train_t;
//int recvfile(int netfd)
//{
//    train_t train;
//    char filename[4096]={0};
//    recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
//    recv(netfd,train.data,train.length,MSG_WAITALL);
//    memcpy(filename,train.data,train.length);
//    int fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    while(1)
//    {
//        bzero(&train,sizeof(train));
//        recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
//        if(train.length<=0)break;
//        recv(netfd,&train.data,train.length,MSG_WAITALL);
//        write(fd,train.data,train.length);
//    }
//    close(fd);
//    return 0;
//}
//v3.1
//int recvfile(int netfd)
//{
//    train_t train;
//    char filename[4096]={0};
//    recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
//    recv(netfd,train.data,train.length,MSG_WAITALL);
//    memcpy(filename,train.data,train.length);
//    int fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    while(1)
//    {
//        bzero(&train,sizeof(train));
//        recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
//        if(train.length<=0)break;
//        recv(netfd,&train.data,train.length,MSG_WAITALL);
//        write(fd,train.data,train.length);
//    }
//    close(fd);
//    return 0;
//}
//v3.1.2
//int recvn(int netfd,void *buf,int length)
//{
//    int total_len=0;
//    char *p = (char *)buf;
//    while(total_len<length)
//    {
//        ssize_t ret =recv(netfd,p+total_len,length-total_len,0); 
//        total_len += ret;
//    }
//    return 0;
//}
//int recvfile(int netfd)
//{
//    train_t train;
//    char filename[4096]={0};
//    recvn(netfd,&train.length,sizeof(int));
//    recvn(netfd,train.data,train.length);
//    memcpy(filename,train.data,train.length);
//    int fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    off_t filesize;
//    recvn(netfd,&train.length,sizeof(int));
//    recvn(netfd,train.data,train.length);
//    memcpy(&filesize,train.data,train.length);
//    printf("filesize=%ld\n",filesize);
//    off_t cur_idx=0,lastsize=0;off_t slice = filesize/10000;
//    while(1)
//    {
//        bzero(&train,sizeof(train));
//        recvn(netfd,&train.length,sizeof(int));
//        if(train.length==0)break;
//        cur_idx+=train.length;
//        if(cur_idx-lastsize>slice)
//        {
//            printf("%5.2lf%%\r",100.00*cur_idx/filesize);
//            fflush(stdout);
//            lastsize=cur_idx;
//        }
//        recvn(netfd,&train.data,train.length);
//        write(fd,train.data,train.length);
//    }
//    printf("100.00%%\n");
//    close(fd);
//    return 0;
//}
//v5.0
//int recvn(int netfd,void *buf,long length)
//{
//    off_t total_len=0,lastsize=0;
//    char *p = (char *)buf;
//    while(total_len<length)
//    {
//        ssize_t ret =recv(netfd,p+total_len,length-total_len,0); 
//        total_len += ret;
//        if((total_len-lastsize)>(length/10000))
//        {
//            printf("%5.2lf%%\r",100.00*total_len/length);
//            fflush(stdout);
//            lastsize = total_len;
//        }
//    }
//    printf("100.00%%\n");
//    return 0;
//}
//int recvfile(int netfd)
//{
//    train_t train;
//    char filename[4096]={0};
//    recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
//    recv(netfd,train.data,train.length,MSG_WAITALL);
//    memcpy(filename,train.data,train.length);
//    int fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    off_t filesize;
//    recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
//    recv(netfd,train.data,train.length,MSG_WAITALL);
//    memcpy(&filesize,train.data,train.length);
//    printf("filesize=%ld\n",filesize);
//    ftruncate(fd,filesize);
//    char *p=(char*)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//    recvn(netfd,p,filesize);
//    close(fd);
//    munmap(p,filesize);
//    return 0;
//}
// ANSI颜色宏 & 进度条函数
#define COLOR_GREEN "\x1B[32m"
#define COLOR_RESET "\x1B[0m"
void print_progress(double perc) 
{
    int width = 50, pos = width * perc;
    printf("\r[");
    for (int i = 0; i < width; ++i) {
        if (i < pos) printf(COLOR_GREEN "█" COLOR_RESET);
        else printf(" ");
    }
    printf("] %5.1f%%", perc * 100);
    fflush(stdout);
}
int recvn(int netfd, void *buf, long length) 
{
    off_t total_len = 0, lastsize = 0;
    char *p = (char *)buf;
    struct timeval start;
    gettimeofday(&start, NULL);
    while (total_len < length) 
    {
        ssize_t ret = recv(netfd, p + total_len, length - total_len, 0);
        if (ret <= 0) break; 
        total_len += ret;
        long threshold = length / 500;
        if (total_len - lastsize > threshold) {
            struct timeval now;
            gettimeofday(&now, NULL);
            double elapsed = (now.tv_sec - start.tv_sec) + (now.tv_usec - start.tv_usec) / 1000000.0;
            double speed = (total_len / (1024.0 * 1024.0)) / elapsed;
            double remain = (length - total_len) / (1024.0 * 1024.0 * speed);
            print_progress((double)total_len / length);
            printf(" | %.1f MB/s | ETA: %.0fs", speed, remain);
            lastsize = total_len;
        }
    }
    print_progress(1.0); 
    printf("\n");
    return (total_len == length) ? 0 : -1;
}
int recvfile(int netfd)
{
    train_t train;
    char filename[4096]={0};
    recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
    recv(netfd,train.data,train.length,MSG_WAITALL);
    memcpy(filename,train.data,train.length);
    int fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
    off_t filesize;
    recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
    recv(netfd,train.data,train.length,MSG_WAITALL);
    memcpy(&filesize,train.data,train.length);
    printf("filesize=%ld\n",filesize);
    ftruncate(fd,filesize);
    char *p=(char*)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    recvn(netfd,p,filesize);
    close(fd);
    munmap(p,filesize);
    return 0;
}
int main(int argc, char *argv[])
{   
    ARGS_CHECK(argc,3);
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port=htons(atoi(argv[2]));
    addr.sin_addr.s_addr=inet_addr(argv[1]);
    int connect1=connect(sockfd,((struct sockaddr *)&addr),sizeof(addr));
    ERROR_CHECK(connect1,-1,"connect failed");
    recvfile(sockfd);
    close(sockfd);
    return 0;
}

